package com.goldgewicht.francois.google.wave.extensions.robots.drmaps;

import java.util.logging.Logger;

import com.goldgewicht.francois.google.wave.extensions.robots.drmaps.util.GoogleMapsApiHelper;
import com.goldgewicht.francois.google.wave.extensions.robots.drmaps.util.GoogleMapsApiPlacemark;
import com.google.wave.api.AbstractRobotServlet;
import com.google.wave.api.Blip;
import com.google.wave.api.Event;
import com.google.wave.api.Image;
import com.google.wave.api.RobotMessageBundle;
import com.google.wave.api.TextView;
import com.google.wave.api.Wavelet;

/**
 * The main servlet for Dr. Maps robot.
 * 
 * @author francois.goldgewicht@gmail.com (Francois Goldgewicht)
 */
public class DrMapsServlet extends AbstractRobotServlet
{

	private static final Logger log = Logger.getLogger(DrMapsServlet.class.getName());

	// The Robot usage instructions
	private static String USAGE_INSTRUCTIONS = "Hello!\nUsage:\n/map address\nExample:\n/map 1600 amphitheatre parkway mountain view";

	// The Robot command prefix
	private static String COMMAND_PREFIX = "/map";

	// The default map zoom
	private static String DEFAULT_MAP_ZOOM = "15";

	// The default map size
	private static String DEFAULT_MAP_SIZE = "350x350";

	// The default map type
	private static String DEFAULT_MAP_TYPE = "roadmap";

	@Override
	public void processEvents(RobotMessageBundle robotMessageBundle)
	{
		// Retrieves the wavelet
		Wavelet wavelet = robotMessageBundle.getWavelet();

		// If the event is "Wavelet self added"
		if (robotMessageBundle.wasSelfAdded())
		{
			processWaveletSelfAddedEvent(wavelet);
		}
		else
		{
			// If the event is "Blip submitted"
			for (Event event : robotMessageBundle.getBlipSubmittedEvents())
			{
				processBlipSubmittedEvent(event.getBlip());
			}
		}
	}

	/**
	 * Processes the event: Wavelet self added.
	 * 
	 * @param wavelet
	 *            the wavelet
	 */
	private void processWaveletSelfAddedEvent(Wavelet wavelet)
	{
		// Displays instructions
		Blip blip = wavelet.appendBlip();
		TextView textView = blip.getDocument();
		textView.append(USAGE_INSTRUCTIONS);
	}

	/**
	 * Processes the event: Blip submitted.
	 * 
	 * @param blip
	 *            the blip
	 */
	private void processBlipSubmittedEvent(Blip blip)
	{
		// Initializes the response
		String response = null;

		// Retrieves the content of the blip
		String blipDocumentText = null;
		if (blip.getBlipId().equals(blip.getWavelet().getRootBlipId()))
		{
			// Root blip : blip content is wavelet title
			blipDocumentText = blip.getWavelet().getTitle();
		}
		else
		{
			blipDocumentText = blip.getDocument().getText();
		}

		log.info("Received blip: '" + blipDocumentText + "'");

		// If this content is a robot command
		if (blipDocumentText != null && blipDocumentText.startsWith(COMMAND_PREFIX))
		{
			// Extracts the address in the command
			String address = blipDocumentText.substring(COMMAND_PREFIX.length()).trim();

			if (address.length() > 0)
			{
				generateResponseForAddress(blip.getDocument(), address);
			}
			else
			{
				response = "Error: please indicate an address.";
			}
		}

		// Renders response
		if (response != null)
		{
			blip.getDocument().append("\n" + response);
		}
	}

	/**
	 * Generates the robot response for a typed address
	 * 
	 * @param document
	 *            the document
	 * @param address
	 *            the address
	 */
	private void generateResponseForAddress(TextView document, String address)
	{
		// Invokes Google Maps API Geocoding service to convert address to geographic coordinates
		GoogleMapsApiPlacemark placemark = GoogleMapsApiHelper.geocodeAddress(address);

		if (placemark != null)
		{
			if (placemark.getSiblingCount() == 0)
			{
				document.append("\nFound 1 address: " + placemark.getAddress());
			}
			else
			{
				document.append("\nFound " + (placemark.getSiblingCount() + 1) + " adresses, first of which is: " + placemark.getAddress());
			}

			// Generates map image URL
			String mapImageUrl = GoogleMapsApiHelper.computeMapImageUrl(placemark.getCoordinates(), DEFAULT_MAP_ZOOM, DEFAULT_MAP_SIZE, DEFAULT_MAP_TYPE);

			// Generates link to Google Maps site URL
			String mapSiteUrl = GoogleMapsApiHelper.computeMapSiteUrl(address);

			// Completes response
			document.append("\nHere is a little map:\n");

			document.append("\n "); // Little hack to add the image after a line break
			Image mapImage = new Image();
			mapImage.setProperty("url", mapImageUrl);
			document.appendElement(mapImage);

			document.append("\nFor the big map, see Google Maps: " + mapSiteUrl);
		}
		else
		{
			document.append("\nError: cannot retrieve map for this address");
		}
	}

}
